package com.lijin.batchsys.framework.schedule;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerUtils;
import org.quartz.impl.StdSchedulerFactory;

import com.lijin.batchsys.framework.common.BatchCache;
import com.lijin.batchsys.framework.common.BatchSysConstants;
import com.lijin.batchsys.framework.common.BatchSysException;
import com.lijin.batchsys.framework.dao.model.BatchInfo;
import com.lijin.batchsys.framework.enums.BatchRunType;

public class BatchQuartzLauncher {

	private static final Logger logger = Logger.getLogger(BatchQuartzLauncher.class);
	
	private static Scheduler scheduler = null;
	
	/**
	 * 系统启动时根据批次信息表来对批次执行情况进行初始化
	 */
	public static void initBatchSchedule() {
		List<BatchInfo> batchInfoList = BatchCache.getInstance().getBatchInfoList();
		try {
			scheduler = new StdSchedulerFactory().getScheduler();
			for (BatchInfo batchInfo : batchInfoList) {
				BatchRunType runTp = BatchRunType.parseByCode(batchInfo.getBatchRunType());
				switch (runTp) {
					case ONE_TIME_DAILY:
						logger.info("批次【" + batchInfo.getBatchNo() + "-" + batchInfo.getBatchDesc() + "】将于每日【" + batchInfo.getBatchRunTmConfig() + "】定时执行");
						scheduleDailyOneTimeJob(batchInfo);
						break;
					case MULTI_TIMES_DAILY:
						logger.info("批次【" + batchInfo.getBatchNo() + "-" + batchInfo.getBatchDesc() + "】将于每日【" + batchInfo.getBatchRunTmConfig() + "】定时执行");
						scheduleDailyMultiTimesJob(batchInfo);
						break;
					case CYCLING:
						logger.info("批次【" + batchInfo.getBatchNo() + "-" + batchInfo.getBatchDesc() + "】将于每日【" + batchInfo.getBatchRunTmConfig() + "】定时执行");
						scheduleCylingJob(batchInfo);
						break;
					case HAND_HOLD:
						logger.info("批次【" + batchInfo.getBatchNo() + "-" + batchInfo.getBatchDesc() + "需人工手动拉起执行");
						break;
				}
			}
			scheduler.start();
		} catch (Exception e) {
			logger.error("初始化批量调度器失败", e);
			throw new BatchSysException("初始化批量错误", e);
		}
	}
	
	/**
	 * 系统停止时停止调度器
	 */
	public static void stopBatchSchedule() {
		try {
			if (scheduler != null && !scheduler.isShutdown()) {
				scheduler.shutdown();
			}
		} catch (SchedulerException e) {
			logger.error("停止批量调度器出错", e);
			throw new BatchSysException("停止批量调度器出错", e);
		}
	}
	
	/**
	 * 每日一次批次
	 * @param jobList
	 * @param batchName
	 * @throws SchedulerException 
	 */
	private static void scheduleDailyOneTimeJob(BatchInfo batchInfo) throws SchedulerException {
		JobDetail jobDetail = new JobDetail();
		jobDetail.setName(BatchSysConstants.DAILY_ONE_TIME + "_JOB_" + batchInfo.getBatchNo());
		jobDetail.setGroup(BatchSysConstants.DAILY_ONE_TIME + "_JOBGROUP_" + batchInfo.getBatchNo());
		jobDetail.setJobClass(BatchQuartzLauncherJob.class);
		
		JobDataMap dataMap = new JobDataMap();
		dataMap.put(BatchSysConstants.SCHEDULE_BATCH_NO_KEY, batchInfo.getBatchNo());
		jobDetail.setJobDataMap(dataMap);
		
		String runTime = batchInfo.getBatchRunTmConfig();
		int[] timeArr = splitRuntime(runTime.trim());
		Trigger trigger = TriggerUtils.makeDailyTrigger(timeArr[0], timeArr[1]);
		trigger.setName(BatchSysConstants.DAILY_ONE_TIME + "_TRIGGER_" + batchInfo.getBatchNo());
		
		scheduler.scheduleJob(jobDetail, trigger);
	}
	
	/**
	 * 每日多次批次
	 * @param scheduler
	 * @param batchInfo
	 * @throws SchedulerException
	 */
	private static void scheduleDailyMultiTimesJob(BatchInfo batchInfo) throws SchedulerException {
		
		JobDataMap dataMap = new JobDataMap();
		dataMap.put(BatchSysConstants.SCHEDULE_BATCH_NO_KEY, batchInfo.getBatchNo());
		
		String[] runTimes = batchInfo.getBatchRunTmConfig().split("\\|");
		for (int i = 0; i < runTimes.length; i ++) {
			JobDetail jobDetail = new JobDetail();
			jobDetail.setName(BatchSysConstants.DAILY_MULTI_TIMES + "_JOB_" + batchInfo.getBatchNo() + "_" + i);
			jobDetail.setGroup(BatchSysConstants.DAILY_MULTI_TIMES + "_JOBGROUP_" + batchInfo.getBatchNo());
			jobDetail.setJobClass(BatchQuartzLauncherJob.class);
			
			jobDetail.setJobDataMap(dataMap);
			
			int[] timeArr = splitRuntime(runTimes[i].trim());
			Trigger trigger = TriggerUtils.makeDailyTrigger(timeArr[0], timeArr[1]);
			trigger.setName(BatchSysConstants.DAILY_MULTI_TIMES + "_TRIGGER_" + batchInfo.getBatchNo() + "_" + i);
			scheduler.scheduleJob(jobDetail, trigger);
		}
	}
	
	/**
	 * 每日按指定秒数循环执行批次
	 * @param batchInfo
	 * @throws SchedulerException 
	 */
	private static void scheduleCylingJob(BatchInfo batchInfo) throws SchedulerException {
		JobDetail jobDetail = new JobDetail();
		jobDetail.setName(BatchSysConstants.CYCLING + "_JOB_" + batchInfo.getBatchNo());
		jobDetail.setGroup(BatchSysConstants.CYCLING + "_JOBGROUP_" + batchInfo.getBatchNo());
		jobDetail.setJobClass(BatchQuartzLauncherJob.class);
		
		JobDataMap dataMap = new JobDataMap();
		dataMap.put(BatchSysConstants.SCHEDULE_BATCH_NO_KEY, batchInfo.getBatchNo());
		jobDetail.setJobDataMap(dataMap);
		
		Trigger trigger = TriggerUtils.makeSecondlyTrigger(Integer.parseInt(batchInfo.getBatchRunTmConfig()));
		trigger.setName(BatchSysConstants.CYCLING + "_TRIGGER_" + batchInfo.getBatchNo());
		trigger.setStartTime(new Date());
		
		scheduler.scheduleJob(jobDetail, trigger);
	}
	
	/**
	 * 将MM:SS的时间字符串解析为一个整数数组返回，第一个是小时，第二个是分钟
	 * @return
	 */
	private static int[] splitRuntime(String runTimeStr) {
		if (StringUtils.isEmpty(runTimeStr)) {
			throw new IllegalArgumentException("传入的日期字符串不能为空");
		}
		int[] timeArr = new int[2];
		String[] timeStrArr = runTimeStr.split(":");
		if (timeStrArr == null || timeStrArr.length != 2) {
			throw new IllegalArgumentException("传入的日期字符串有误：" + runTimeStr); 
		}
		timeArr[0] = Integer.parseInt(timeStrArr[0]);
		timeArr[1] = Integer.parseInt(timeStrArr[1]);
		return timeArr;
	}
}
